var numeric = require("numeric");

/**
 * 数字类型枚举
 */
class NumberByte {
  static Float64 = 0;
  static Int8 = 1;
  static Int16 = 2;
  static Int32 = 3;
  static Int64 = 4;
  static Uint8 = 5;
  static Uint16 = 6;
  static Uint32 = 7;
  static Uint64 = 8;
  static PositiveInfinity = 9;
  static NegativeInfinity = 10;
  static Nan = 11;
  static TypeLength = {
    [NumberByte.Float64]: 8,
    [NumberByte.Int8]: 1,
    [NumberByte.Int16]: 2,
    [NumberByte.Int32]: 4,
    [NumberByte.Int64]: 8,
    [NumberByte.Uint8]: 1,
    [NumberByte.Uint16]: 2,
    [NumberByte.Uint32]: 4,
    [NumberByte.Uint64]: 8,
    [NumberByte.PositiveInfinity]: 0,
    [NumberByte.NegativeInfinity]: 0,
    [NumberByte.Nan]: 0,
  };

  /**
   * 获取数字的最小可压缩内存长度
   * @param {Number} number 数字
   * @returns {Number} 数字内存长度
   */
  static Size(number) {
    let type = this.__Type__(number);
    return this.TypeLength[type];
  }

  /**
   * 获取数字序列化为内存数组的最小可压缩长度
   * @param {Number} number 数字
   * @returns {Number} 长度
   */
  static ParseSize(number) {
    return this.Size(number) + 1;
  }

  /**
   * 获取字节数组
   * @param {Number} number 数字
   * @returns {ArrayBuffer} 字节数组
   */
  static ToByte(number) {
    let type = this.__Type__(number);
    let buffer = new ArrayBuffer(1 + this.TypeLength[type]);
    let byte = new DataView(buffer);
    byte.setUint8(0, type);
    switch (type) {
      case this.Float64:
        byte.setFloat64(1, number);
        break;
      case this.Int8:
        byte.setInt8(1, number);
        break;
      case this.Int16:
        byte.setInt16(1, number);
        break;
      case this.Int32:
        byte.setInt32(1, number);
        break;
      case this.Int64:
        byte.setBigInt64(1, number);
        break;
      case this.Uint8:
        byte.setUint8(1, number);
        break;
      case this.Uint16:
        byte.setUint16(1, number);
        break;
      case this.Uint32:
        byte.setUint32(1, number);
        break;
      case this.Uint64:
        byte.setBigUint64(1, number);
        break;
      case this.PositiveInfinity:
      case this.NegativeInfinity:
      case this.Nan:
        break;
    }
    return buffer;
  }

  /**
   * 设置字节数组
   * @param {DataView} bytes 字节数组
   * @param {Number} number 数值
   */
  static SetByte(bytes, number) {
    if (bytes.byteLength < this.ParseSize(number)){
      console.error("Number.SetByte(): 字节数组长度不足.")
      return;
    }
    let type = this.__Type__(number);
    bytes.setUint8(0, type);
    switch (type) {
      case this.Float64:
        bytes.setFloat64(1, number);
        break;
      case this.Int8:
        bytes.setInt8(1, number);
        break;
      case this.Int16:
        bytes.setInt16(1, number);
        break;
      case this.Int32:
        bytes.setInt32(1, number);
        break;
      case this.Int64:
        bytes.setBigInt64(1, number);
        break;
      case this.Uint8:
        bytes.setUint8(1, number);
        break;
      case this.Uint16:
        bytes.setUint16(1, number);
        break;
      case this.Uint32:
        bytes.setUint32(1, number);
        break;
      case this.Uint64:
        bytes.setBigUint64(1, number);
        break;
      case this.PositiveInfinity:
      case this.NegativeInfinity:
      case this.Nan:
        break;
    }
  }

  /**
   * 从字节数组获取
   * @param {ArrayBuffer} buffer 字节数组
   * @param {Number} offset 偏移量
   * @returns { {"number": Number, "offset": Number} } 数值的偏移量
   */
  static FromByte(buffer, offset) {
    let byte = new DataView(buffer);
    let type = byte.getUint8(offset);
    if (type > 11) {
      throw "Number.FromByte(): Not a valid number byte.";
    }
    let number = 0;
    switch (type) {
      case this.Float64:
        number = byte.getFloat64(offset + 1);
        break;
      case this.Int8:
        number = byte.getInt8(offset + 1);
        break;
      case this.Int16:
        number = byte.getInt16(offset + 1);
        break;
      case this.Int32:
        number = byte.getInt32(offset + 1);
        break;
      case this.Int64:
        number = byte.getBigInt64(offset + 1);
        break;
      case this.Uint8:
        number = byte.getUint8(offset + 1);
        break;
      case this.Uint16:
        number = byte.getUint16(offset + 1);
        break;
      case this.Uint32:
        number = byte.getUint32(offset + 1);
        break;
      case this.Uint64:
        number = byte.getBigUint64(offset + 1);
        break;
      case this.PositiveInfinity:
        number = Number.POSITIVE_INFINITY;
        break;
      case this.NegativeInfinity:
        number = Number.NEGATIVE_INFINITY;
        break;
      case this.Nan:
        number = Number.NaN;
        break;
    }
    return { number: number, offset: 1 + this.TypeLength[type] };
  }

  /**
   * 获取数字类型
   * @param {Number} number 数字
   * @returns 数字类型
   */
  static __Type__(number) {
    if (Number.POSITIVE_INFINITY == number) {
      return NumberByte.PositiveInfinity;
    }
    if (Number.NEGATIVE_INFINITY == number) {
      return NumberByte.NegativeInfinity;
    }
    if (Number.isNaN(number)) {
      return NumberByte.Nan;
    }
    if (!Number.isInteger(number)) {
      return NumberByte.Float64;
    }
    if (number < -9223372036854775808n) {
      return NumberByte.Float64;
    }
    if (number < -2147483648) {
      return NumberByte.Int64;
    }
    if (number < -32768) {
      return NumberByte.Int32;
    }
    if (number < -128) {
      return NumberByte.Int16;
    }
    if (number < 0) {
      return NumberByte.Int8;
    }
    if (number <= 255) {
      return NumberByte.Uint8;
    }
    if (number <= 65535) {
      return NumberByte.Uint16;
    }
    if (number <= 4294967295) {
      return NumberByte.Uint32;
    }
    if (number <= 18446744073709551615n) {
      return NumberByte.Uint64;
    }
    return NumberByte.Float64;
  }
}

/**
 * 二维矩阵
 */
class Matrix2d {
  /**
   * 二维矩阵
   * @param {Number} row_size 行大小
   * @param {Number} col_size 列大小
   * @param {Array<Array<Number>> | null} array2d 原始数据
   */
  constructor(row_size, col_size, array2d = null) {
    this.__AHP_TYPE__ = "Matrix2d";
    this.__row_size__ = row_size;
    this.__col_size__ = col_size;
    this.__data__ = [];
    if (array2d != null) {
      let avaliable = Matrix2d.__CheckArray2d__(row_size, col_size, array2d);
      if (!avaliable) {
        throw "Error from AHP.Matrix2d: 矩阵大小与原始array2d不一致.";
      }
      this.__data__ = array2d;
    } else {
      this.__data__ = [];
      for (let row = 0; row < row_size; row++) {
        this.__data__.push(new Array(col_size).fill(0));
      }
    }
  }

  /**
   * 设置某行某列的一个值
   * @param {Number} row 行号
   * @param {Number} col 列号
   * @param {Number} value 值
   */
  setValue = function (row, col, value) {
    this.__data__[row][col] = value;
  };

  /**
   * 获取某行某列的一个值
   * @param {Number} row 行号
   * @param {Number} col 列号
   * @returns 值
   */
  getValue = function (row, col) {
    return this.__data__[row][col];
  };

  /**
   * 插入一行
   * @param {Number} position 索引号, 指示插入为第position行. 为负数时在末尾插入
   * @param {Array<Number> | null} data 要插入的数据, 长度应等于当前列数
   */
  insertRow = function (position = -1, data = null) {
    if (data != null && data.length != this.__col_size__) {
      throw "Error from AHP.Matrix2d.insertRow: data长度与当前列数不匹配.";
    }

    if (position > this.__row_size__ || position < 0) {
      position = this.__row_size__;
    }
    ++this.__row_size__;
    if (data == null) {
      data = new Array(this.__col_size__).fill(0);
    }
    this.__data__.splice(position, 0, data);
  };

  /**
   * 插入一列
   * @param {Number} position 索引号, 指示插入为第position列. 为负数时在末尾插入
   * @param {Array<Number> | null} data 要插入的数据, 长度应等于当前行数
   */
  insertColumn = function (position = -1, data = null) {
    if (data != null && data.length != this.__row_size__) {
      throw "Error from AHP.Matrix2d.insertColumn: data长度与当前行数不匹配.";
    }

    if (position > this.__col_size__ || position < 0) {
      position = this.__col_size__;
    }
    ++this.__col_size__;
    if (data == null) {
      data = new Array(this.__col_size__).fill(0);
    }
    this.__data__.forEach((element, index) => {
      element.splice(position, 0, data[index]);
    });
  };

  /**
   * 删除一行
   * @param {Number} position 索引号
   */
  deleteRow = function (position) {
    if (position < 0 && position >= this.__row_size__) {
      throw "Error from AHP.Matrix2d.deleteRow: position不合法.";
    }
    --this.__row_size__;
    this.__data__.splice(position, 1);
  };

  /**
   * 删除一列
   * @param {Number} position 索引号
   */
  deleteColumn = function (position) {
    if (position < 0 && position >= this.__col_size__) {
      throw "Error from AHP.Matrix2d.deleteColumn: position不合法.";
    }
    --this.__col_size__;
    this.__data__.forEach((element) => {
      element.splice(position, 1);
    });
  };

  /**
   * 获取总行数
   * @returns {Number} 总行数
   */
  rowSize = function () {
    return this.__row_size__;
  };

  /**
   * 获取总列数
   * @returns {Number} 总列数
   */
  columnSize = function () {
    return this.__col_size__;
  };

  /**
   * 获取内部数组
   * @returns {Array<Array<Number>>} 内部数组
   */
  data = function () {
    return this.__data__;
  };

  /**
   * 转换为字节数组
   * @returns {ArrayBuffer} 字节数组
   */
  toByte = function () {
    if (this.__col_size__ == 0 && this.__row_size__ == 0) {
      return new Uint8Array(0).buffer;
    }

    let offset = 0;
    let buffer = new Uint8Array(
      (this.__col_size__ * this.__row_size__ + 4) * 8
    );

    let byte = new Uint8Array(NumberByte.ToByte(this.__row_size__));
    buffer.set(byte, offset);
    offset += byte.byteLength;

    byte = new Uint8Array(NumberByte.ToByte(this.__col_size__));
    buffer.set(byte, offset);
    offset += byte.byteLength;

    for (let row = 0; row < this.__row_size__; row++) {
      for (let col = 0; col < this.__col_size__; col++) {
        byte = new Uint8Array(NumberByte.ToByte(this.__data__[row][col]));
        buffer.set(byte, offset);
        offset += byte.byteLength;
      }
    }
    let real_bytes = new Uint8Array(offset);
    real_bytes.set(buffer.subarray(0, offset));
    return real_bytes.buffer;
  };

  /**
   * 转换为JSON字符串
   * @returns {string} JSON字符串
   */
  toJSON = function () {
    return JSON.stringify(this.__data__);
  };

  /**
   * 检查二维数组是否合法
   * @param {Number} row_size 行数
   * @param {Number} col_size 列数
   * @param {Array<Array<Number>>} array2d 二维数组
   * @returns {boolean} 合法性
   */
  static __CheckArray2d__ = function (row_size, col_size, array2d) {
    if (array2d.length != row_size) {
      return false;
    }
    for (let row = 0; row < row_size; row++) {
      let array = array2d[row];
      if (array.length === undefined || array.length != col_size) {
        return false;
      }
    }
    return true;
  };

  /**
   * 从字节数组反序列化二维矩阵
   * @param {ArrayBuffer} byte 字节数组
   * @returns {Matrix2d} 二维矩阵
   */
  static FromByte = function (byte) {
    if (byte.byteLength == 0) {
      return new Matrix2d(0, 0);
    }
    let offset = 0;
    let result = NumberByte.FromByte(byte, offset);
    offset += result.offset;
    let row_size = result.number;

    result = NumberByte.FromByte(byte, offset);
    offset += result.offset;
    let col_size = result.number;

    let matrix = new Matrix2d(row_size, col_size);
    for (let row = 0; row < matrix.rowSize(); row++) {
      for (let col = 0; col < matrix.columnSize(); col++) {
        result = NumberByte.FromByte(byte, offset);
        matrix.setValue(row, col, result.number);
        offset += result.offset;
      }
    }
    return matrix;
  };

  /**
   * 从JSON字符反序列化二维矩阵
   * @param {string} json JSON字符串
   * @returns 二维矩阵
   */
  static FromJSON = function (json) {
    let array2d = JSON.parse(json);
    let row = array2d.length;
    if (row == 0) {
      return Matrix2d(0, 0);
    }
    let col = array2d[0].length;
    return new Matrix2d(row, col, array2d);
  };
}

/**
 * 层次分析矩阵
 */
class AHPMatrix {
  /**
   * 层次分析矩阵
   * @param {Array<string>} names 因素名称
   */
  constructor(names) {
    let set = new Set(names);
    if (set.length != names.length) {
      names = Array.from(set);
    }

    this.__size__ = names.length;
    this.__names__ = names;
    this.__matrix__ = new Matrix2d(this.__size__, this.__size__);
    for (let index = 0; index < this.__size__; index++) {
      this.__matrix__.setValue(index, index, 1);
    }
    this.balance();
  }

  /**
   * 获取内部因素数量
   * @returns {Number} 大小
   */
  size = function () {
    return this.__size__;
  };

  /**
   * 获取内部因素名称列表
   * @returns {Array<string>} 因素名称列表
   */
  names = function () {
    return this.__names__;
  };

  /**
   * 获取内部矩阵
   * @returns {Matrix2d} 矩阵
   */
  matrix = function () {
    return this.__matrix__;
  };

  /**
   * 获取当前行列的值
   * @param { Number | string } row 行索引号/行名称
   * @param { Number | string } col 列索引号/列名称
   * @returns { Number | null } 值
   */
  getValue = function (row, col) {
    if (typeof row == "string") {
      let row_index = this.__names__.indexOf(row);
      if (row_index == -1) {
        console.error(
          `Error from AHP.AHPMatrix.getValue: 不存在名称为${row}的因素.`
        );
        return null;
      }
      row = row_index;
    }
    if (typeof col == "string") {
      let col_index = this.__names__.indexOf(col);
      if (col_index == -1) {
        console.error(
          `Error from AHP.AHPMatrix.getValue: 不存在名称为${row}的因素.`
        );
        return null;
      }
      col = col_index;
    }
    return this.__matrix__.getValue(row, col);
  };

  /**
   * 修改当前行列的值
   * @param { Number | string } row 行索引号/行名称
   * @param { Number | string } col 列索引号/列名称
   * @param { Number } value 值
   */
  setValue = function (row, col, value) {
    if (value == null) {
      console.error("Error from AHP.AHPMatrix.setValue: value不能为null.");
      return;
    }
    if (typeof row == "string") {
      let row_index = this.__names__.indexOf(row);
      if (row_index == -1) {
        console.error(
          `Error from AHP.AHPMatrix.setValue:  不存在名称为${row}的因素.`
        );
        return;
      }
      row = row_index;
    }
    if (typeof col == "string") {
      let col_index = this.__names__.indexOf(col);
      if (col_index == -1) {
        console.error(
          `Error from AHP.AHPMatrix.setValue:  不存在名称为${col}的因素.`
        );
        return;
      }
      col = col_index;
    }
    this.__matrix__.setValue(row, col, value);
    this.__singleBalance__(row, col);
  };

  /**
   * 修改一个因素名称
   * @param {string} oldName 原因素名称
   * @param {string} newName 新的因素名称
   */
  changeItemName = function (oldName, newName) {
    let index = this.__names__.indexOf(oldName);
    if (index == -1) {
      console.error(
        `AHP.AHPMatrix.changeItemName: 不存在名称为${oldName}的因素.`
      );
      return;
    }
    this.__names__.splice(index, 1, newName);
  };

  /**
   * 添加一个因素
   * @param {string} name 因素名称
   * @param {Number} position 位置
   */
  insertItem = function (name, position = -1) {
    if (this.__names__.indexOf(name) != -1) {
      console.error(
        `AHP.AHPMatrix.changeItemName: 名称为${name}的因素已经存在.`
      );
      return;
    }
    if (position > this.__size__ || position < 0) {
      position = this.__size__;
    }
    ++this.__size__;
    this.__names__.splice(position, 0, name);
    this.__matrix__.insertRow(position);
    this.__matrix__.insertColumn(position);
    this.balance();
  };

  /**
   * 删除一个因素
   * @param { Number | string } item 因素索引号/因素名称
   * @returns
   */
  deleteItem = function (item) {
    if (typeof item == "string") {
      let index = this.__names__.indexOf(item);
      if (index == -1) {
        console.error(`AHP.AHPMatrix.deleteItem: 名称为${item}的因素不存在.`);
        return;
      }
      item = index;
    } else {
      if (item < 0 || item >= this.__size__) {
        console.error(`AHP.AHPMatrix.deleteItem: 因素索引号超出范围.`);
        return;
      }
    }
    --this.__size__;
    this.__names__.splice(item, 1);
    this.__matrix__.deleteRow(item);
    this.__matrix__.deleteColumn(item);
    this.balance();
  };

  /**
   * 强制平衡当前层次分析矩阵
   */
  balance = function () {
    for (let row = 0; row < this.__size__; row++) {
      for (let col = row; col < this.__size__; col++) {
        this.__singleBalance__(row, col);
      }
    }
  };

  /**
   * 验证当前层次分析矩阵数值合法性
   * @returns {boolean} 合法性
   */
  available = function () {
    if (this.__size__ == 0) {
      return false;
    }
    for (let row = 0; row < this.__size__; row++) {
      for (let col = row; col < this.__size__; col++) {
        if (!this.__singleAvailable__(row, col)) {
          return false;
        }
      }
    }
    return true;
  };

  /**
   * 判断因素名称是否存在
   * @param {string} name 因素名称
   * @returns 是否存在
   */
  existName = function (name) {
    return this.__names__.indexOf(name) != -1;
  };

  /**
   * 序列化为字节数组
   * @returns {ArrayBuffer} 字节数组
   */
  toByte = function () {
    if (this.__size__ == 0) {
      return new Uint8Array(0).buffer;
    }
    let matrix_bytes = this.__matrix__.toByte();

    let name_size = 2;
    this.__names__.forEach((element) => {
      name_size += 2 + element.length;
    });

    let total_bytes = new Uint8Array(name_size * 8 + matrix_bytes.byteLength);
    let offset = 0;
    let number_byte = NumberByte.ToByte(this.__size__);
    total_bytes.set(new Uint8Array(number_byte), offset);
    offset += number_byte.byteLength;

    let encoder = new TextEncoder();

    this.__names__.forEach((element) => {
      let name_byte = encoder.encode(element);
      number_byte = NumberByte.ToByte(name_byte.byteLength);
      total_bytes.set(new Uint8Array(number_byte), offset);
      offset += number_byte.byteLength;
      total_bytes.set(name_byte, offset);
      offset += name_byte.byteLength;
    });

    total_bytes.set(new Uint8Array(matrix_bytes), offset);
    offset += matrix_bytes.byteLength;

    let real_bytes = new Uint8Array(offset);
    real_bytes.set(total_bytes.subarray(0, offset));
    return real_bytes.buffer;
  };

  /**
   * 转换为Base64字符串
   * @returns {string} Base64
   */
  toBase64 = function () {
    let bytes = this.toByte();
    return btoa(String.fromCharCode(...new Uint8Array(bytes)));
  };

  /**
   * 返回一个描述矩阵的对象
   * @returns {object} 对象
   */
  toObject = function () {
    let object = {};
    for (let row = 0; row < this.__size__; row++) {
      let inner_object = {};
      for (let col = 0; col < this.__size__; col++) {
        inner_object[this.__names__[col]] = this.getValue(row, col);
      }
      object[this.__names__[row]] = inner_object;
    }
    return object;
  };

  /**
   * 序列化为JSON字符串
   * @returns {string} JSON 字符串
   */
  toJSON = function () {
    let object = {
      names: this.__names__,
      data: this.__matrix__.data(),
    };
    return JSON.stringify(object);
  };

  /**
   * 渲染到控制台
   */
  render = function () {
    console.table(this.toObject());
  };

  /**
   * 获取当前特征值与特征向量
   * @returns { {value: Number, vector: Array<Number>} | null } value: 特征值, vector: 特征向量
   */
  eigen = function () {
    if (this.__size__ == 0) {
      return null;
    }
    let data = this.__matrix__.data();
    if (data.every(item => item.every(item1 => item1 == 1))) {
      return { value: 0, vector: new Array(this.__size__).fill(1 / this.__size__) };
    }
    let eigen = numeric.eig(this.__matrix__.data());
    //特征值数组
    let eigenValueList = eigen.lambda.x;
    //最大特征值
    let maxEigenValue = -1;
    let maxEigenValueIndex = -1;
    eigenValueList.forEach((value, index) => {
      if (value > maxEigenValue) {
        maxEigenValue = value;
        maxEigenValueIndex = index;
      }
    });
    let eigenVector = eigen.E.x;
    eigenVector = numeric.transpose(eigenVector);
    eigenVector = eigenVector[maxEigenValueIndex];

    //返回最大特征值与特征向量
    return { value: maxEigenValue, vector: eigenVector };
  };

  /**
   * 获取一致性指标值
   * @returns {Number} 一致性指标
   */
  CI = function () {
    if (this.__size__ == 0) {
      return 0;
    }
    if (!this.available()) {
      return 0;
    }
    let eigen = this.eigen();
    if (this.__size__ == 1) {
      return 0;
    }
    return (eigen.value - this.__size__) / (this.__size__ - 1);
  };

  /**
   * 获取检验系数
   * @returns {Number} 检验系数
   */
  CR = function () {
    if (this.__size__ == 0) {
      return 0;
    }
    if (!this.available()) {
      return 0;
    }
    let ri = this.__RI__();
    if (ri == 0) {
      return 0;
    }
    return this.CI() / ri;
  };

  /**
   * 是否通过一致性检验
   * @returns {boolean} 是否通过
   */
  consitstenceAvailable = function () {
    if (this.__size__ == 0) {
      return false;
    }
    if (this.__size__ == 1 || this.__size__ == 2) {
      return true;
    }
    let cr = this.CR();
    return cr < 0.1;
  };

  /**
   * 权重
   * @returns { object | null } 权重
   */
  weight = function () {
    if (!this.consitstenceAvailable()) {
      return null;
    }
    let eigen = this.eigen();
    let vector = AHPMatrix.__Normalize__(eigen.vector);
    let weightObject = {};
    for (let index = 0; index < this.__names__.length; index++) {
      const element = this.__names__[index];
      weightObject[element] = vector[index];
    }
    return weightObject;
  };

  /**
   * 单个单元格平衡
   * @param {Number} row 行索引号
   * @param {Number} col 列索引号
   */
  __singleBalance__ = function (row, col) {
    let value = this.__matrix__.getValue(row, col);
    if (row == col) {
      this.__matrix__.setValue(row, col, 1);
    } else if (value == 0) {
      this.__matrix__.setValue(col, row, 0);
    } else {
      this.__matrix__.setValue(col, row, 1 / value);
    }
  };

  /**
   * 单个单元格验证合法性
   * @param {Number} row 行索引号
   * @param {Number} col 列索引号
   * @returns {boolean} 合法性
   */
  __singleAvailable__ = function (row, col) {
    let value = this.__matrix__.getValue(row, col);
    if (row == col) {
      if (value != 1) {
        return false;
      } else {
        return true;
      }
    }
    if (value == 0 || 1 / value != this.__matrix__.getValue(col, row)) {
      return false;
    }
    return true;
  };

  /**
   * 随机一致性指标
   * @returns {Number} RI
   */
  __RI__ = function () {
    let n = [
      0, 0, 0, 0.52, 0.89, 1.12, 1.26, 1.36, 1.41, 1.46, 1.49, 1.52, 1.54, 1.56,
      1.58, 1.59, 1.6, 1.61, 1.62, 1.63, 1.64, 1.646, 1.649, 1.655, 1.658,
      1.663, 1.667, 1.669, 1.672,
    ];
    if (this.__size__ > n.length) {
      return n[n.length - 1];
    }
    return n[this.__size__];
  };

  /**
   * 从字节数组获取层次分析法矩阵
   * @param {ArrayBuffer} bytes 字节数组
   * @returns {AHPMatrix} 层次分析法矩阵
   */
  static FromByte = function (bytes) {
    if (bytes.byteLength == 0) {
      return AHPMatrix([]);
    }
    let total_bytes = new DataView(bytes);
    let offset = 0;

    let result = NumberByte.FromByte(bytes, offset);
    let size = result.number;
    offset += result.offset;

    let decoder = new TextDecoder();
    let names = [];
    for (let index = 0; index < size; index++) {
      result = NumberByte.FromByte(bytes, offset);
      let name_size = result.number;
      offset += result.offset;
      names.push(decoder.decode(new Uint8Array(bytes, offset, name_size)));
      offset += name_size;
    }
    let matrix_bytes = new Uint8Array(total_bytes.byteLength - offset);
    matrix_bytes.set(
      new Uint8Array(bytes).subarray(offset, total_bytes.byteLength - 1)
    );
    let matrix = Matrix2d.FromByte(matrix_bytes.buffer);
    return this.FromMatrix2d(names, matrix);
  };

  /**
   * 从二维矩阵创建层次分析矩阵
   * @param {Array<string>} names 名称
   * @param {Matrix2d} matrix2d 二维矩阵
   * @returns {AHPMatrix} 层次分析矩阵
   */
  static FromMatrix2d = function (names, matrix2d) {
    if (
      matrix2d.__AHP_TYPE__ === null ||
      matrix2d.__AHP_TYPE__ === undefined ||
      matrix2d.__AHP_TYPE__ !== "Matrix2d"
    ) {
      throw "AHP.AHPMatrix.FromMatrix2d: 参数必须为AHP.Matrix2d.";
    }
    if (
      names.length != matrix2d.columnSize() ||
      names.length != matrix2d.rowSize()
    ) {
      throw "AHP.AHPMatrix.FromMatrix2d: 因素名称与Matrix2d大小不一致.";
    }
    let matrix = new this(names);
    matrix.__matrix__ = matrix2d;
    matrix.balance();
    return matrix;
  };

  /**
   * 从JSON反序列化为AHP矩阵
   * @param {string} json JSON字符串
   * @returns {AHPMatrix} AHP矩阵
   */
  static FromJSON = function (json) {
    let object = JSON.parse(json);
    return this.FromArray2d(object.names, object.data);
  };

  /**
   * 从数组创建层次分析矩阵
   * @param {Array<string>} names 因素名称
   * @param {Array<Array<Number>>} array2d 二维double数组
   * @returns {AHPMatrix} 层次分析矩阵
   */
  static FromArray2d = function (names, array2d) {
    let size = names.length;
    let matrix = new this(names);
    matrix.__matrix__ = new Matrix2d(size, size, array2d);
    matrix.balance();
    return matrix;
  };

  /**
   * 从Base64反序列化层次分析矩阵
   * @param {string} base64 Base64字符串
   * @returns {AHPMatrix} 层次分析矩阵
   */
  static FromBase64 = function (base64) {
    let bytes = Uint8Array.from(atob(base64), char => char.charCodeAt(0));
    return AHPMatrix.FromByte(bytes.buffer);
  };

  /**
   * 从对象转换为层次分析矩阵
   * @param {Array<String>} names 因素名称
   * @param {string} object 对象
   * @returns {AHPMatrix} 层次分析矩阵
   */
  static FromObject = function(names, object) {
    let matrix = new this(names);
    for (let row in object) {
      for (let col in object[row]) {
        matrix.setValue(row, col, object[row][col]);
      }
    }
    return matrix;
  }

  /**
   * 从层次分析矩阵创建层次分析矩阵
   * @param {Array<string>} names 因素名称列表
   * @param {AHPMatrix} ahp 层次分析矩阵
   */
  static FromAHP = function (names, ahp) {
    let matrix = new AHPMatrix(names);
    for (let row = 0; row < names.length; row++) {
      for (let col = row + 1; col < names.length; col++) {
        if (!ahp.existName(names[row]) || !ahp.existName(names[col])) {
          continue;
        }
        let value = ahp.getValue(names[row], names[col]);
        matrix.setValue(row, col, value);
      }
    }
    return matrix;
  };

  /**
   * 数组归一化
   * @param {Array<Number>} vector 数组
   * @returns 归一化后的数组
   */
  static __Normalize__ = function (vector) {
    let total = vector.reduce(function (prev, curr) {
      return prev + curr;
    });
    return Array.from(vector, (x) => x / total);
  };
}

export default {
  Matrix2d,
  AHPMatrix,
};
